Retirement Planning


Kerry Back

BUSI 721, Fall 2022
JGSB, Rice University


  • Let’s track a retirement account balance monthly.
  • For simplicity, assume the return is the same each month.
  • We’ll first track it in a loop, then use future values.

Our goal

  • Today is date 0, date 1 is 1 month away, \(\ldots\)
  • Date R (R months away) is our retirement date
  • We plan to live until date \(T>R\).
  • We make deposits at dates \(1, 2, \ldots, R\)
  • We make withdrawals at the beginning of each month of retirement: dates \(R, R+1, \ldots, T-1\)

  • Our account balance today is \(B_0\).
  • We earn a monthly return \(r\).
  • At date 1, we have \((1+r)B_0\) and deposit \(D_1\), so \(B_1 = (1+r)B_0 + D_1\).
  • Likewise, \(B_2 = (1+r)B_1 + D_2\). This is the future value \((1+r)^2 B_0 + (1+r)D_1 + D_2\)
  • Etc., until

\[B_R = (1+r)^R B_0 + (1+r)^{R-1} D_1 + \cdots + D_R\]

  • At date \(R\), we also make a withdrawal \(W_R\)
  • Then earn \(r\) and make another withdrawal \(W_{R+1}\).
  • The account balance evolves, always as the future value of all prior deposits and withdrawals.

Deposit and withdrawal arrays

  • Let D be an array of deposits (of length \(R\)).
  • Let W be an array of withdrawals (of length \(T-R\)).
  • To escape the normal counting from zero, let’s make them dictionaries with keys being the dates \(1, \ldots, R, \ldots, T\).
D = {i: d for i, d in zip(range(1, R+1), D)}
W = {i: w for i, w in zip(range(R, T), W)}

Example

  • Assume deposits grow at some rate \(g\), so \(D_t = (1+g)D_{t-1}\).
  • Assume withdrawals grow (or decline) at some rate \(h\), so \(W_t = (1+h)W_{t-1}\)
R = 30*12      # 30 years until retirement
T = 60*12      # 60 total years
r = 0.005      # earn 1/2 % per month  (~ 6% per year)
B0 = 100000    # initial balance is $100,000
D1 = 1000      # initial savings is $1,000 (per month)
W1 = 10000     # withdraw $10,000 first month in retirement
g = 0.002      # deposit is 0.2% larger each month
h = 0          # withdrawals are constant

Deposits and withdrawals

D = D1 * (1+g)**np.arange(R)
W = W1 * (1+h)**np.arange(T-R)

D = {i: d for i, d in zip(range(1, R+1), D)}
W = {i: w for i, w in zip(range(R, T), W)}

Account balance

B = np.zeros(T+1)
B[0] = B0

for t in range(1, R+1) :               
    B[t] = (1+r)*B[t-1] + D[t] 

B[R] -= W[R]

for t in range(R+1, T):
    B[t] = (1+r)*B[t-1] - W[t]

B[T] = (1+r)*B[T-1]

Final balance as sum of future values

# future value of initial balance
FVB = B0 * (1+r)**T

# future values of deposits
fvFactors = (1+r)**np.arange(T-1, T-R-1, -1)
FVD = np.sum(D * fvFactors)

# future values of withdrawals
fvFactors = (1+r)**np.arange(T-R, 0, -1)
FVW = np.sum(W * fvFactors)

# account balance at end
BT = FVB + FVD - FVW

Final balance one more way

x = (1+r)**T

grFactors = (1+g)**np.arange(R)
fvFactors = (1+r)**np.arange(T-1, T-R-1, -1)
y = np.sum(grFactors*fvFactors)

grFactors = (1+h)**np.arange(T-R)
fvFactors = (1+r)**np.arange(T-R, 0, -1)
z = np.sum(grFactors*fvFactors)

BT = x*B0 + y*D1 - z*W1

# example: solve for D1 to make BT=0
D1 = (z*W1 - x*B0) / y

Success!